/*
 * Copyright (c) 2010, Nikolaus Moll
 * All rights reserved.
 */
package net.miblounge.gradecalculator.gui.dialogs;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import net.miblounge.gradecalculator.core.AdaptedRegulations;
import net.miblounge.gradecalculator.core.descriptors.courses.Course;
import net.miblounge.gradecalculator.core.student.ExaminationResult;
import net.miblounge.gradecalculator.core.student.ExaminationResultType;
import net.miblounge.gradecalculator.grade.ICourseGrade;
import net.miblounge.gradecalculator.grade.IGradeFactory;
import net.miblounge.gradecalculator.grade.IGradeValidator;
import net.miblounge.gradecalculator.guicommon.dialogs.AbstractDialog;
import net.miblounge.miglayout.qt.MigLayout;

import com.trolltech.qt.gui.QCheckBox;
import com.trolltech.qt.gui.QGroupBox;
import com.trolltech.qt.gui.QLabel;
import com.trolltech.qt.gui.QLineEdit;
import com.trolltech.qt.gui.QWidget;

public abstract class AbstractResultDialog extends AbstractDialog
{
    private final IGradeFactory fab;
    private final QLineEdit[] leGrades;

    private QCheckBox cbUngradedResult;
    private QWidget groupEstimated;

    private final Course course;
    private final ExaminationResult examinationResult;

    private final AdaptedRegulations regulations;

    public AbstractResultDialog(final QWidget parent, final AdaptedRegulations regulations, final Course course)
    {
        super(parent);
        setWindowTitle(tr("Result"));
        this.fab = regulations.getGradeFactory();
        this.course = course;
        this.regulations = regulations;
        this.examinationResult = regulations.getStudent().getResult(course);

        this.leGrades = new QLineEdit[ExaminationResultType.values().length];

        setClientArea(createClientArea());

        setResults();

        revalidate();
    }

    protected abstract boolean hasGradedPerformance();

    protected abstract boolean hasUngradedPerformance();

    protected abstract boolean hasEstimatedGroup();

    protected abstract String getCourseName();

    protected void setEstimationEnabled(final boolean enabled)
    {
        groupEstimated.setEnabled(enabled);
    }

    @Override
    protected List<QWidget> createAdditonalWidgets(final QWidget parent)
    {
        return new Vector<QWidget>();
    }

    private QWidget createClientArea()
    {
        final QWidget result = new QWidget();
        final MigLayout layout = new MigLayout("", "[grow]", "");
        result.setLayout(layout);

        layout.addWidget(createActualGrade(result), "growx, wrap");
        if (hasEstimatedGroup()) {
            groupEstimated = createEstimatedGroup(result);
            layout.addWidget(groupEstimated, "growx, wrap");
        }

        for (final QWidget widget : createAdditonalWidgets(result)) {
            layout.addWidget(widget, "growx, wrap");
        }

        return result;
    }

    protected QGroupBox createActualGrade(final QWidget parent)
    {
        final QGroupBox result = new QGroupBox(tr("Actual grade for ") + getCourseName(), parent);
        final MigLayout layout = new MigLayout("", "[][grow, 100:100:200]", "[]5[]");
        result.setLayout(layout);

        if (hasGradedPerformance()) {
            final QLabel labelGrade = new QLabel(tr("Grade:"), result);
            labelGrade.setToolTip(course.getGradedPerformance().toDetailedString());
            layout.addWidget(labelGrade, "sg lg");
            final QLineEdit leGrade = new QLineEdit(result);
            leGrade.textEdited.connect(this, "revalidate()");
            layout.addWidget(leGrade, "wrap");

            setGradeEdit(ExaminationResultType.PASSED, leGrade);
        }

        if (hasUngradedPerformance()) {
            final QLabel labelPractical = new QLabel(tr("Practical"));
            labelPractical.setToolTip(course.getUngradedPerformance().toDetailedString());
            layout.addWidget(labelPractical, "sg lg");
            cbUngradedResult = new QCheckBox(tr("passed"), result);
            layout.addWidget(cbUngradedResult, "growx, wrap");

        }
        else {
            cbUngradedResult = null;
        }

        return result;
    }

    protected QGroupBox createEstimatedGroup(final QWidget parent)
    {
        final QGroupBox result = new QGroupBox(tr("Estamted Results for ") + getCourseName(), parent);
        final MigLayout layout = new MigLayout("", "[][grow, 100:100:200]", "[]5[]");
        result.setLayout(layout);

        for (final ExaminationResultType type : ExaminationResultType.values()) {
            if (type == ExaminationResultType.PASSED) {
                continue;
            }

            layout.addWidget(new QLabel(type.getName(), result), "sg lg");
            final QLineEdit lineEdit = new QLineEdit(result);
            lineEdit.textEdited.connect(this, "revalidate()");
            layout.addWidget(lineEdit, "wrap");

            setGradeEdit(type, lineEdit);
        }

        return result;
    }

    protected IGradeFactory getFab()
    {
        return fab;
    }

    protected void setGradeEdit(final ExaminationResultType type, final QLineEdit lineEdit)
    {
        setGradeEdit(type.ordinal(), lineEdit);
    }

    protected void setGradeEdit(final int index, final QLineEdit lineEdit)
    {
        leGrades[index] = lineEdit;
    }

    protected QLineEdit getGradeEdit(final ExaminationResultType type)
    {
        return getGradeEdit(type.ordinal());
    }

    protected QLineEdit getGradeEdit(final int index)
    {
        return leGrades[index];
    }

    @Override
    protected boolean validate()
    {
        if (!hasGradedPerformance()) {
            return super.validate();
        }

        final boolean isEstimated = leGrades[ExaminationResultType.PASSED.ordinal()].text().trim().equals("");
        setEstimationEnabled(isEstimated);

        final IGradeValidator validator = fab.getValidator();

        if (isEstimated) {
            for (final ExaminationResultType type : ExaminationResultType.values()) {
                if (type == ExaminationResultType.PASSED) {
                    continue;
                }

                final QLineEdit le = leGrades[type.ordinal()];
                if (!validator.isValid(le.text())) {
                    return false;
                }
            }
        }
        else {
            if (!validator.isValid(leGrades[ExaminationResultType.PASSED.ordinal()].text())) {
                return false;
            }
        }

        return super.validate();
    }

    public Map<ExaminationResultType, String> getGrades()
    {
        final Map<ExaminationResultType, String> result = new HashMap<ExaminationResultType, String>();

        final boolean isEstimated = leGrades[ExaminationResultType.PASSED.ordinal()].text().trim().equals("");

        if (isEstimated) {
            for (final ExaminationResultType type : ExaminationResultType.values()) {
                if (type == ExaminationResultType.PASSED) {
                    continue;
                }

                final QLineEdit le = leGrades[type.ordinal()];
                final ICourseGrade grade = fab.createCourseGrade(le.text(), 1);
                result.put(type, grade.getGrade());
            }
        }
        else {
            final ICourseGrade grade = fab
                    .createCourseGrade(leGrades[ExaminationResultType.PASSED.ordinal()].text(), 1);
            result.put(ExaminationResultType.PASSED, grade.getGrade());
        }

        // if (leGrade != null) {
        // if (getGradedResult() == Result.NONE) {
        // return "";
        // }
        // return leGrade.text();
        // }

        return result;
    }

    protected ExaminationResult getResult()
    {
        return examinationResult;
    }

    protected void setResults()
    {
        if (hasUngradedPerformance()) {
            cbUngradedResult.setChecked(examinationResult.getUngradedPassed());
        }

        for (final ExaminationResultType type : ExaminationResultType.values()) {
            final String gradeText = examinationResult.getGrade(type);

            final QLineEdit lineEdit = getGradeEdit(type);
            if (lineEdit == null) {
                continue;
            }
            lineEdit.setText(gradeText);
            if (type == ExaminationResultType.PASSED) {
                lineEdit.setFocus();
                lineEdit.setSelection(0, gradeText.length());
            }
        }
    }

    public boolean getUngradedPassed()
    {
        if (cbUngradedResult != null) {
            return cbUngradedResult.isChecked();
        }

        return false;
    }

    protected Course getCourse()
    {
        return course;
    }

    protected void setGradedPerformanceEnabled(final boolean enabled)
    {
        getGradeEdit(ExaminationResultType.PASSED).setEnabled(enabled);
        if (!enabled) {
            setEstimationEnabled(false);
        }
        else {
            final boolean isEstimated = leGrades[ExaminationResultType.PASSED.ordinal()].text().trim().equals("");
            setEstimationEnabled(isEstimated);
        }
    }

    protected void setUngradedPerformanceEnabled(final boolean enabled)
    {
        cbUngradedResult.setEnabled(enabled);
    }

    @Override
    public void apply()
    {
        super.apply();
        regulations.getStudent().addResult(getResult());
    }
}
